package com.wedroid.r2d2.app;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.wedroid.r2d2.contact.Contact;
import com.wedroid.r2d2.contact.ContactManager;
import com.wedroid.r2d2.http.RequestManager;
import com.wedroid.r2d2.message.MessageManager;
import com.wedroid.r2d2.support.ResponseResult;
import com.wedroid.r2d2.support.response.InitResponse;
import com.wedroid.r2d2.support.response.SyncCheckResponse;
import com.wedroid.r2d2.support.response.login.LoginStatus;
import com.wedroid.r2d2.support.sync.SyncAction;
import com.wedroid.r2d2.support.sync.SyncSelector;

/**
 * @author lute
 *
 */
@Component
public class DroidManager implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(DroidManager.class);

    private static final String QR_URL = "https://login.weixin.qq.com/qrcode/";

    @Autowired
    private RequestManager requestManager;

    @Autowired
    private ContactManager contactManager;

    @Autowired
    private MessageManager messageManager;

    private DroidStatus status;

    private String uuid;

    private Contact user;

    /**
     *
     */
    public DroidManager() {
        this.status = DroidStatus.READY;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    public void run() {
        try {
            boolean polling = pollLoginStatus();
            if (!polling) {
                return;
            }

            // Redirect to post login URL and get relevant data
            boolean redirect = requestManager.postLoginRedirect();
            if (!redirect) {
                logger.trace("#run - Post login redirect fails...");
                return;
            }

            // Get initialization data
            ResponseResult<InitResponse> result = requestManager.init();
            if (!result.isValid()) {
                logger.trace("#run - Init response fails...");
                return;
            }
            user = result.getValue().getUser();
            List<Contact> contacts = result.getValue().getContacts();
            contactManager.intialize(user, contacts);

            // Check status notify
            requestManager.statusNotify();

            // Request contacts
            contactManager.requestContacts();

            // Start to begin handle WeChat events
            process();
        } catch (Exception e) {
            logger.trace("#run - Exception occurs during dorid running: {}", e);
            requestManager.shutdown();
        } finally {
            status = DroidStatus.READY;
            uuid = null;
        }
    }

    /**
     * @return
     */
    public synchronized DroidStatus start() {
        if (status.equals(DroidStatus.READY)) {
            uuid = requestManager.getUUID();
            if (StringUtils.isNotBlank(uuid)) {
                status = DroidStatus.WAIT_LOGIN;

                Thread thread = new Thread(this);
                thread.setName("DroidManager");
                thread.start();
            }
        }
        return status;
    }

    /**
     *
     */
    private boolean pollLoginStatus() {
        int tip = 1;
        int waitSeconds = 1;
        int retryTimes = 10;
        while (retryTimes > 0) {
            LoginStatus loginStatus = requestManager.requestLoginStatus(uuid, tip);
            switch (loginStatus) {
            case SUCCESS:
                status = DroidStatus.RUNNING;
                return true;
            case SCANNED:
                tip = 0;
                logger.trace("#pollLoginStatus - User scanned the QR but has not confirmed it.");
                break;
            default:
               tip = 1;
               retryTimes -= 1;
               try {
                   Thread.sleep(waitSeconds * 1000);
               } catch (InterruptedException e) {
                   logger.error("#pollLoginStatus - Sleeping thread encounters interrupted exception: {}", e);
               }
               if (loginStatus.isTimeout()) {
                   logger.trace("#pollLoginStatus - WeChat login timeouts.");
               } else {
                   logger.trace("#pollLoginStatus - WeChat login poll fails with returnde code [{}]", loginStatus.getCode());
               }
               // FIXME handle retryTimes decrease to 0
            }
        }
        return false;
    }

    /**
     *
     */
    private void process() {
        while (true) {

            ResponseResult<SyncCheckResponse> result = requestManager.syncCheck();
            if (result.isValid()) {
                // Get response
                SyncCheckResponse response = result.getValue();

                // Get sync action and selector
                SyncAction action = response.getAction();
                SyncSelector selector = response.getSelector();
                switch (action) {
                    case SYNCING:
                        if (!selector.equals(SyncSelector.NONE)) {
                            // Currently, different selector seems no affect..
                            messageManager.syncMessages();
                        } else {
                            logger.warn("#process - Get sync selector [{}]", selector);
                        }
                        break;
                    case LOGOUT:
                    case OUT:
                        logger.trace("#process - WeChat Web logout...");
                        return;
                    default:
                        logger.trace("#process - Get sync action [{}] and selector [{}].", action, selector);
                        try {
                            Thread.sleep(10 * 1000);
                        } catch (InterruptedException e) {
                            logger.error("#process - Process is interrupted.");
                        }
                        return;
                }
            }
        }
    }

    /**
     * Get QR code image URL
     * @return
     */
    public String getQR() {
        return StringUtils.isBlank(uuid) ? null : QR_URL + uuid;
    }

    /**
     * @return the status
     */
    public DroidStatus getStatus() {
        return status;
    }

}
